﻿// Brandon Haynes - http://brandonhaynes.org
// Copyright (c) 2008
// by Brandon Haynes

// Please refer to the project license, located at http://www.codeplex.com/DNNLocalization/license

// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.

//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
//USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

using System;
using System.Collections;
using System.IO;
using System.Resources;
using System.Security.Permissions;
using System.Xml;

namespace BrandonHaynes.DotNetNukeResXBuildProvider
	{
	public class TolerantResXResourceReader : IResourceReader
		{
		private Stream InputStream { get; set; }
		private IResourceReader StrictReader { get; set; }

		[PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust"), PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
		public TolerantResXResourceReader(Stream inputStream, string basePath, bool useResXDataNodes)
			{
			InputStream = inputStream;
			StrictReader = new ResXResourceReader(inputStream)
				{ 
				BasePath = basePath, 
				UseResXDataNodes = useResXDataNodes 
				};
			}

		#region Tolerance-Related Methods
		private ResXResourceReader GenerateTolerantReader()
			{
			XmlDocument document = new XmlDocument();
			InputStream.Seek(0, SeekOrigin.Begin);

			document.Load(InputStream);

			document.DocumentElement.AppendChild(CreateResHeader(document, "resmimetype", "text/microsoft-resx"));
			document.DocumentElement.AppendChild(CreateResHeader(document, "version", "2.0"));
			document.DocumentElement.AppendChild(CreateResHeader(document, "reader", "System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"));
			document.DocumentElement.AppendChild(CreateResHeader(document, "writer", "System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"));


			return new ResXResourceReader(new StringReader(document.OuterXml));
			}

		private static XmlElement CreateResHeader(XmlDocument document, string name, string value)
			{
			var resheader = document.CreateElement("resheader");
			var valueNode = document.CreateElement("value");
			var resheaderNameAttribute = document.CreateAttribute("name");

			resheaderNameAttribute.Value = name;
			valueNode.AppendChild(document.CreateTextNode(value));

			resheader.Attributes.Append(resheaderNameAttribute);
			resheader.AppendChild(valueNode);

			return resheader;
			}

		private static bool IsMissingResheaderException(ArgumentException exception)
			{
			return !string.IsNullOrEmpty(exception.Message) && exception.Message.Contains(@"Cannot find valid ""resheader"" tags");
			}
		#endregion

		#region IResourceReader Members

		public void Close()
			{
			StrictReader.Close();
			}

		public IDictionaryEnumerator GetEnumerator()
			{
			try
				{
				return StrictReader.GetEnumerator();
				}
			catch (ArgumentException exception)
				{
				if (IsMissingResheaderException(exception))
					{
					StrictReader = GenerateTolerantReader();
					return StrictReader.GetEnumerator();
					}
				else
					throw;
				}
			}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
			{
			try
				{
				return StrictReader.GetEnumerator();
				}
			catch (ArgumentException exception)
				{
				if (IsMissingResheaderException(exception))
					{
					StrictReader = GenerateTolerantReader();
					return ((IEnumerable)StrictReader).GetEnumerator();
					}
				else
					throw;
				}
			}

		#endregion

		#region IDisposable Members

		public void Dispose()
			{
			Dispose(true);
			GC.SuppressFinalize(this);
			}

		protected virtual void Dispose(bool disposing)
			{
			if(disposing)
				StrictReader.Dispose();
			}

		~TolerantResXResourceReader()
			{
			Dispose(false);
			}

		#endregion
		}
	}
